package util

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"github.com/gorilla/websocket"
	"github.com/sirupsen/logrus"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

var Log = logrus.New()

// 初始化日志
func init() {
	Log.SetFormatter(&logrus.TextFormatter{
		ForceColors:     true,
		FullTimestamp:   true,
		TimestampFormat: "2006-01-02 15:04:05",
	})
	Log.SetOutput(os.Stdout)
	Log.SetLevel(logrus.InfoLevel)
}

// ServerRoute 路由
func ServerRoute(ip string, port int) (route string) {
	return "ws://" + ip + ":" + strconv.Itoa(port) + "/ws/watchlog"
}

// 获取本机ip
func RealIp() string {
	ips := ""
	ifaces, err := net.Interfaces()
	if err != nil {
		Log.Info("无法获取网络接口信息：", err)
		return ips
	}
	for _, iface := range ifaces {
		addrs, err := iface.Addrs()
		if err != nil {
			Log.Info("无法获取 IP 地址：", err)
			continue
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			// 跳过非 IPv4 地址
			if ip == nil || ip.IsLoopback() || ip.To4() == nil {
				continue
			}
			//fmt.Println("本机 IP 地址为：", ip.String())
			//ips[index] = ip.String()
			return ip.String()
		}
	}

	return ""
}

// 判断数组中是否包含某个元素
func Contains(arr []string, val string) bool {
	for _, n := range arr {
		if val == n {
			return true
		}
	}
	return false
}

// 加密
func Encrypt(key, plaintext []byte) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return "", err
	}

	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)

	return base64.URLEncoding.EncodeToString(ciphertext), nil
}

// 解密
func Decrypt(key []byte, ciphertext string) ([]byte, error) {
	ciphertextBytes, err := base64.URLEncoding.DecodeString(ciphertext)
	if err != nil {
		return nil, err
	}

	if len(ciphertextBytes) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}

	iv := ciphertextBytes[:aes.BlockSize]
	ciphertextBytes = ciphertextBytes[aes.BlockSize:]

	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	stream := cipher.NewCTR(block, iv)
	stream.XORKeyStream(ciphertextBytes, ciphertextBytes)

	return ciphertextBytes, nil
}

type MacAddress struct {
	address net.HardwareAddr
}

func NewMacAddress() (*MacAddress, error) {
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	for _, iface := range interfaces {
		if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 {
			address := iface.HardwareAddr
			if len(address) == 6 {
				return &MacAddress{address: address}, nil
			}
		}
	}

	return nil, errors.New("cannot determine MAC address")
}

func (m *MacAddress) String() string {
	return m.address.String()
}

func (m *MacAddress) Bytes() []byte {
	return m.address
}

// QueryParams 解析get请求的参数
func QueryParams(queryPath string) (params map[string]string) {
	groups := strings.Split(GetURI(queryPath, 1), "&")
	var m = make(map[string]string)
	if len(groups) > 0 {
		for _, group := range groups {
			data := strings.Split(group, "=")
			m[data[0]] = data[1]
		}
	}
	return m
}

// GetURI 获取请求路径
func GetURI(url string, index int8) string {
	return strings.Split(url, "?")[index]
}

// WebSocketClientExist 判断socket的客户端是否存在
func WebSocketClientExist(clients []*websocket.Conn, conn *websocket.Conn) bool {
	for _, client := range clients {
		if strings.EqualFold(conn.RemoteAddr().String(), client.RemoteAddr().String()) {
			return true
		}
	}
	return false
}

func GetFmtTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func GetLogType(logContent string) int8 {
	//1 Debug：最详细的日志信息，通常只在调试时使用。
	//2 Info：用于描述程序运行过程中的重要信息，例如请求处理时间等。
	//3 Warning：表示潜在的错误情形，可能会引起系统问题，但不会导致系统崩溃。
	//4 Error：表示已经发生了错误，例如程序中的异常情况，需要进行记录和处理。
	//5 Fatal：表示致命错误，会导致程序的崩溃，需要进行紧急处理。
	if strings.Contains(logContent, "Debug") {
		return 1
	} else if strings.Contains(logContent, "INFO") {
		return 2
	} else if strings.Contains(logContent, "Warning") {
		return 3
	} else if strings.Contains(logContent, "Error") {
		return 4
	} else if strings.Contains(logContent, "Fatal") {
		return 5
	}
	return 0
}
